#include <jni.h>
#include <string>
#include <malloc.h>
#include "gif/gif_lib.h"
#include <android/bitmap.h>

#define  argb(a, r, g, b) (((a & 0xFF)<<24 ) | ((b & 0xFF)<<16) | ((g & 0xFF)<<8) | (r & 0xFF))
typedef struct GIF_BEAN {
//    播放当前帧数
    int currentFrame;
//    下一帧的播放时长  数组
    int *delays;
} GifBean;

void drawFrame(GifFileType *gifFile, GifBean *gifBean, AndroidBitmapInfo info, void *pixels);

extern "C" {
JNIEXPORT jlong JNICALL
Java_com_example_tys_gif_GifProcess_loadGif(JNIEnv *env, jobject instance, jstring path_) {
    const char *path = env->GetStringUTFChars(path_, 0);
    int error;
    GifFileType *gifFile = DGifOpenFileName(path, &error);
    DGifSlurp(gifFile);//Call DGifOpenFileName() or DGifOpenFileHandle() first to initialize I/O

    GifBean *gifBean = (GifBean *) malloc(sizeof(GifBean));
    memset(gifBean, 0, sizeof(GifBean));
    gifFile->UserData = gifBean;
    gifBean->delays = (int *) malloc(sizeof(int) * gifFile->ImageCount);
    memset(gifBean->delays, 0, sizeof(int) * gifFile->ImageCount);

    //每帧图片播放延时
    ExtensionBlock *extensionBlock = NULL;
    for (int i = 0; i < gifFile->ImageCount; ++i) {
        //savedImage 当前图像信息 & 扩展块
        SavedImage frame = gifFile->SavedImages[i]; //high-level API
        for (int j = 0; j < frame.ExtensionBlockCount; ++j) {
            //图形控制扩展块
            if (GRAPHICS_EXT_FUNC_CODE == frame.ExtensionBlocks[j].Function) {//0xf9
                extensionBlock = &frame.ExtensionBlocks[j];
                break;
            }
        }
        if (extensionBlock) {
            // 第三个字节  5 延迟时间	第二个字节   6	延迟时间	D
            int frame_delay =
                    10 * ((extensionBlock->Bytes[2] << 8) | extensionBlock->Bytes[1]);//高8位 + 低8位
            gifBean->delays[i] = frame_delay;
        }
    }
    env->ReleaseStringUTFChars(path_, path);
    return (jlong) gifFile;
}

JNIEXPORT jint JNICALL
Java_com_example_tys_gif_GifProcess_getWidth(JNIEnv *env, jobject instance, jlong gifPoint) {
    GifFileType *gifFile = (GifFileType *) gifPoint;
    return gifFile->SWidth;
}

JNIEXPORT jint JNICALL
Java_com_example_tys_gif_GifProcess_getHeight(JNIEnv *env, jobject instance, jlong gifPoint) {
    GifFileType *gifFile = (GifFileType *) gifPoint;
    return gifFile->SHeight;
}

JNIEXPORT jint JNICALL
Java_com_example_tys_gif_GifProcess_updateFrame(JNIEnv *env, jobject instance, jobject bitmap,
                                                jlong gifPoint) {
    GifFileType *gifFileType = (GifFileType *) gifPoint;
    GifBean *gifBean = (GifBean *) gifFileType->UserData;

    AndroidBitmapInfo androidBitmapInfo;
    AndroidBitmap_getInfo(env, bitmap, &androidBitmapInfo);//android/bitmap.h


    void *pixel; //像素二维数组
    //Locking will ensure that the memory for the pixels will not move until the unlockPixels call
    AndroidBitmap_lockPixels(env, bitmap, &pixel);
    //绘制一帧图像
    drawFrame(gifFileType, gifBean, androidBitmapInfo, pixel);

    gifBean->currentFrame++;
    if (gifBean->currentFrame >= gifFileType->ImageCount - 1) {
        gifBean->currentFrame = 0;
    }
    AndroidBitmap_unlockPixels(env, bitmap);
    return gifBean->delays[gifBean->currentFrame];
}
}

void drawFrame(GifFileType *gifFile, GifBean *gifBean, AndroidBitmapInfo bitmapInfo, void *pixels) {

    SavedImage savedImage = gifFile->SavedImages[gifBean->currentFrame];
    GifImageDesc frameInfo = savedImage.ImageDesc;
    ColorMapObject *colorMapObject = frameInfo.ColorMap; //字典

    int pointPixel;//索引
    GifColorType gifColorType;
    //bitmapInfo.stride : The number of byte per row
    int *px = (int *) ((char *) pixels + bitmapInfo.stride * frameInfo.Top);
    int *line;
    for (int y = frameInfo.Top; y < frameInfo.Top + frameInfo.Height;  ++y) {
        line = px;
        for (int x = frameInfo.Left; x < frameInfo.Left + frameInfo.Width; ++x) {
            pointPixel = (y - frameInfo.Top) * frameInfo.Width + (x - frameInfo.Left);
            GifByteType gifByteType = savedImage.RasterBits[pointPixel];//char
            gifColorType = colorMapObject->Colors[gifByteType];
            line[x] = argb(255, gifColorType.Red, gifColorType.Green, gifColorType.Blue);
        }
        //一行
        px = (int *) ((char *) px + bitmapInfo.stride);
    }


}

